package com.lx.composetest.lowlatency

import android.graphics.Color
import android.opengl.GLES20
import android.util.Log
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer

/**
 * OpenGL Renderer class responsible for drawing lines
 */
class BezierLineRenderer {
    private var mVertexShader: Int = -1
    private var mFragmentShader: Int = -1
    private var mGlProgram: Int = -1
    private var mPositionHandle: Int = -1
    private var mMvpMatrixHandle: Int = -1
    private var mColorHandle: Int = -1
    private val mColorArray = FloatArray(4)
    private var mVertexBuffer: FloatBuffer? = null
    private val mLineCoords = FloatArray(6)
    fun initialize() {
        release()
        mVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode)
        mFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode)
        mGlProgram = GLES20.glCreateProgram()
        GLES20.glAttachShader(mGlProgram, mVertexShader)
        GLES20.glAttachShader(mGlProgram, mFragmentShader)
        GLES20.glLinkProgram(mGlProgram)
        val bb: ByteBuffer =
            ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float)
                LineCoordsSize * 4
            )
        // use the device hardware's native byte order
        bb.order(ByteOrder.nativeOrder())
        // create a floating point buffer from the ByteBuffer
        mVertexBuffer =  bb.asFloatBuffer().apply {
            put(mLineCoords)
            position(0)
        }
        mPositionHandle = GLES20.glGetAttribLocation(mGlProgram, vPosition)
        mMvpMatrixHandle = GLES20.glGetUniformLocation(mGlProgram, uMVPMatrix)
        mColorHandle = GLES20.glGetUniformLocation(mGlProgram, vColor)
    }

    fun drawCirclesBetweenPoints(
        startX: Float,
        startY: Float,
        endX: Float,
        endY: Float,
        radius: Float,
        numPoints: Int,
        mProgram: Int
    ) {
        // 计算两个点之间的距离
        val dx = endX - startX
        val dy = endY - startY
        val distance = Math.sqrt((dx * dx + dy * dy).toDouble()).toFloat()

        // 计算单位方向向量
        val stepX = dx / distance
        val stepY = dy / distance

        // 设置圆顶点数据
        var vertexBuffer: FloatBuffer?

        // 使用OpenGL ES程序
        GLES20.glUseProgram(mProgram)
        val positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
        GLES20.glEnableVertexAttribArray(positionHandle)

        // 循环绘制每个圆
        for (i in 0 until distance.toInt()) {
            val centerX = startX + i * stepX
            val centerY = startY + i * stepY

            // 生成圆顶点
            val circleVertices = generateCircleVertices(centerX, centerY, radius, numPoints)
            vertexBuffer = ByteBuffer.allocateDirect(circleVertices.size * 4).run {
                order(ByteOrder.nativeOrder())
                asFloatBuffer().apply {
                    put(circleVertices)
                    position(0)
                }
            }

            // 设置顶点数据并绘制圆
            GLES20.glVertexAttribPointer(
                positionHandle, 3,
                GLES20.GL_FLOAT, false,
                0, vertexBuffer
            )
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, numPoints + 2)
        }

        GLES20.glDisableVertexAttribArray(positionHandle)
    }

    private fun generateCircleVertices(
        centerX: Float,
        centerY: Float,
        radius: Float,
        numPoints: Int
    ): FloatArray {
        val vertices =
            FloatArray((numPoints + 2) * 3) // (numPoints + 2) * 3 because of center point and end point
        vertices[0] = centerX // Center point x
        vertices[1] = centerY // Center point y
        vertices[2] = 0f // Center point z
        val angleStep = 2 * Math.PI / numPoints
        for (i in 1..numPoints) {
            val angle = i * angleStep
            val x = (centerX + radius * Math.cos(angle)).toFloat()
            val y = (centerY + radius * Math.sin(angle)).toFloat()
            vertices[i * 3] = x
            vertices[i * 3 + 1] = y
            vertices[i * 3 + 2] = 0f // z coordinate is 0
        }
        // End point same as first point to close the circle
        vertices[(numPoints + 1) * 3] = vertices[3]
        vertices[(numPoints + 1) * 3 + 1] = vertices[4]
        vertices[(numPoints + 1) * 3 + 2] = vertices[5]
        return vertices
    }


    fun release() {
        if (mVertexShader != -1) {
            GLES20.glDeleteShader(mVertexShader)
            mVertexShader = -1
        }
        if (mFragmentShader != -1) {
            GLES20.glDeleteShader(mFragmentShader)
            mFragmentShader = -1
        }
        if (mGlProgram != -1) {
            GLES20.glDeleteProgram(mGlProgram)
            mGlProgram = -1
        }
    }

    fun drawLines(
        mvpMatrix: FloatArray,
        lines: FloatArray,
        color: Int = Color.RED,
        lineWidth: Float = 10f
    ) {
        GLES20.glUseProgram(mGlProgram)
        GLES20.glLineWidth(lineWidth)
        GLES20.glEnableVertexAttribArray(mPositionHandle)
        mColorArray[0] = Color.red(color).toFloat()
        mColorArray[1] = Color.green(color).toFloat()
        mColorArray[2] = Color.blue(color).toFloat()
        mColorArray[3] = Color.alpha(color).toFloat()
        // Set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, mColorArray, 0)
        GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, mvpMatrix, 0)
        Log.i("TAG", "drawLines:lineSize = ${lines.size}")
        drawCirclesBetweenPoints(
            lines[0],
            lines[1],
            lines[2],
            lines[3],
            lineWidth / 2f,
            20,
            mGlProgram
        )
//        mVertexBuffer?.let { buffer ->
//            Log.i("TAG", "drawLines: ${lines[0]}- ${lines[1]} : ${lines[2]}- ${lines[3]}")
//            for (i in 0 until lines.size step 4) {
//                mLineCoords[0] = lines[i]
//                mLineCoords[1] = lines[i + 1]
//                mLineCoords[2] = 0f
//                mLineCoords[3] = lines[i + 2]
//                mLineCoords[4] = lines[i + 3]
//                mLineCoords[5] = 0f
//                buffer.put(mLineCoords)
//                buffer.position(0)
//            }
//            // Prepare the triangle coordinate data
//            GLES20.glVertexAttribPointer(
//                mPositionHandle, CoordsPerVertex,
//                GLES20.GL_FLOAT, false,
//                VertexStride, buffer
//            )
//            GLES20.glDrawArrays(GLES20.GL_LINES, 0, VertexCount)
//        }
//        GLES20.glDisableVertexAttribArray(mPositionHandle)
    }


    companion object {
        const val CoordsPerVertex = 3
        const val LineCoordsSize = 6
        private val VertexCount: Int = LineCoordsSize / CoordsPerVertex
        private val VertexStride: Int = CoordsPerVertex * 4 // 4 bytes per vertex
        private const val uMVPMatrix = "uMVPMatrix"
        private const val vPosition = "vPosition"
        private const val VertexShaderCode =
            """
                uniform mat4 $uMVPMatrix;
                attribute vec4 $vPosition;
                void main() { // the matrix must be included as a modifier of gl_Position
                  gl_Position = $uMVPMatrix * $vPosition;
                }
            """
        private const val vColor = "vColor"
        private const val FragmentShaderCode =
            """
                precision highp float;
                uniform vec4 $vColor;
                void main() {
                    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
                    gl_FragColor = $vColor;
                }
            """
    }
}